/*
 * MIT License
 *
 * Copyright (c) 2018 Alibaba Group
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.tmall.wireless.vaf.virtualview.view.page;

import com.tmall.wireless.vaf.Log;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.VelocityDetector;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.PlainArray;
import com.tmall.wireless.vaf.virtualview.core.Adapter;
import com.tmall.wireless.vaf.virtualview.core.IContainer;

import java.util.ArrayList;
import java.util.List;


/**
 * Created by gujicheng on 16/10/25.
 */
public class PageView extends ComponentContainer implements
        ComponentContainer.ArrangeListener,
        Component.EstimateSizeListener,
        Component.TouchEventListener,
        Component.BindStateChangedListener {
    private final static String TAG = "PageView_TMTEST";

    protected final static int MAX_ITEM_COUNT = 5;
    protected final static int DEFAULT_ANIMATOR_TIME_INTERVAL = 100;
    protected final static int DEFAULT_AUTO_SWITCH_TIME_INTERVAL = 500;
    protected final static int DEFAULT_STAY_TIME = 2500;
    protected final static int MSG_AUTO_SWITCH = 1;
    protected final static int VEL_THRESHOLD = 2000;

    protected PlainArray<List<Adapter.ViewHolder>> mItemCache = new PlainArray<>();

    protected Adapter mAdapter;
    protected int mCurPos;
    protected int mDownPos;
    protected boolean mIsNext;

    protected int mStayTime = DEFAULT_STAY_TIME;
    protected int mAnimatorTimeInterval = DEFAULT_ANIMATOR_TIME_INTERVAL;
    protected int mAutoSwitchTimeInterval = DEFAULT_AUTO_SWITCH_TIME_INTERVAL;

    protected boolean mAutoSwitch = false;
    protected boolean mIsHorizontal = true;
    /**
     * for horizontal layout, children's normal layout orientation is from left to right, reverse layout is from right
     * to left
     * for vetical layout, children's normal layout orientation is from top to bottom, reverse layout is from bottom to
     * top
     */
    protected boolean mLayoutNormal = true;
    protected int mAnimationStyle = 0;
    protected boolean mCanSlide = true;
    protected long mAutoSwitchDelay = 0;

    protected EventHandler mAutoSwitchHandler;

    protected boolean mDataChanged = true;

    //private AnimatorProperty ani;
    private AnimatorValue ani;
//    private ObjectAnimator ani;

//    private int mLastX;
//    private int mLastY;

    //    private VelocityTracker mVelocityTracker;
    private VelocityDetector mVelocityTracker;
//    private int mPointerId;
    private int mMaxVelocity;

    protected MyAnimatorListener mAniListener = new MyAnimatorListener();
    protected Listener mListener;

    protected boolean mCanSwitch = true;


    public interface Listener {
        void onPageFlip(int pos, int total);
    }

    public PageView(Context context) {
        super(context);
        setEstimateSizeListener(this);
        setArrangeListener(this);
        setTouchEventListener(this);
        setBindStateChangedListener(this);

        mCurPos = 0;

        mAutoSwitchHandler = new EventHandler(EventRunner.getMainEventRunner()) {
            @Override
            protected void processEvent(InnerEvent event) {
                //  super.processEvent(event);
                if (MSG_AUTO_SWITCH == event.eventId) {
                    autoSwitch();
                }
            }

//            @Override
//            public void handleMessage(Message msg) {
//                if (MSG_AUTO_SWITCH == msg.what) {
//                    autoSwitch();
//                }
//            }
        };

//        mMaxVelocity = ViewConfiguration.getMaximumFlingVelocity();
        mMaxVelocity = 8000;
    }

    public void setAdapter(Adapter adapter) {
        mAdapter = adapter;
    }

    public void setListener(Listener lis) {
        mListener = lis;
    }

    public void setSlide(boolean slide) {
        mCanSlide = slide;
    }

    public void setAutoSwitchTimeInterval(int time) {
        mAutoSwitchTimeInterval = time;
    }

    public void setAnimatorTimeInterval(int time) {
        mAnimatorTimeInterval = time;
    }

    public void setAnimationStyle(int animationStyle) {
        mAnimationStyle = animationStyle;
    }

    public void setLayoutOrientation(boolean isNormal) {
        mLayoutNormal = isNormal;
    }

    public void setStayTime(int time) {
        mStayTime = time;
    }

    public void setOrientation(boolean isHorizontal) {
        mIsHorizontal = isHorizontal;
    }

    public void setAutoSwitch(boolean auto) {
        mAutoSwitch = auto;
    }

    public void setAutoSwitchDelay(long delay) {
        this.mAutoSwitchDelay = delay;
    }

    public void autoSwitch() {
        mIsNext = true;
        ani = new AnimatorValue();
        if (mIsHorizontal) {
            if (mLayoutNormal) {
//                ani = ObjectAnimator.ofInt(this, "scrollX", 0, this.getMeasuredWidth());
                setHorizontalAnimator(ani, this.getEstimatedWidth());
            } else {
//                ani = ObjectAnimator.ofInt(this, "scrollX", 0, -this.getMeasuredWidth());
                setHorizontalAnimator(ani, -this.getEstimatedWidth());
            }
        } else {
            if (mLayoutNormal) {
//                ani = ObjectAnimator.ofInt(this, "scrollY", 0, this.getMeasuredHeight());
                setVerticalAnimator(ani, this.getEstimatedHeight());
            } else {
//                ani = ObjectAnimator.ofInt(this, "scrollY", 0, -this.getMeasuredHeight());
                setVerticalAnimator(ani, -this.getEstimatedHeight());
            }
        }
//        ani.setDuration(mAutoSwitchTimeInterval).addListener(mAniListener);

        ani.setDuration(mAutoSwitchTimeInterval);
        ani.setStateChangedListener(mAniListener);
//        ani.setInterpolator(getTimeInterpolater());
//        ani.setStartDelay(mAutoSwitchDelay)
        ani.setDelay(mAutoSwitchDelay);
        ani.start();
    }

//    @Override TODO
//    protected void onVisibilityChanged(View changedView, int visibility) {
//        super.onVisibilityChanged(changedView, visibility);
//
//        if (visibility != View.VISIBLE) {
//            mCanSwitch = false;
//            mAutoSwitchHandler.removeMessages(MSG_AUTO_SWITCH);
//        } else {
//            mCanSwitch = true;
//            if (mAutoSwitch && mAdapter.getItemCount() > 1) {
//                mAutoSwitchHandler.removeMessages(MSG_AUTO_SWITCH);
//                mAutoSwitchHandler.sendEmptyMessageDelayed(MSG_AUTO_SWITCH, mStayTime);
//            }
//        }
//    }


    @Override
    public void onComponentBoundToWindow(Component component) {
        refresh();
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        mCanSwitch = false;
        mAutoSwitchHandler.removeEvent(MSG_AUTO_SWITCH);
    }

//    @Override
//    protected void onDetachedFromWindow() {
//        super.onDetachedFromWindow();
//        mCanSwitch = false;
//        mAutoSwitchHandler.removeMessages(MSG_AUTO_SWITCH);
//    }

    public void refresh() {
        mCanSwitch = true;

        if (mDataChanged) {
            if (ani != null) {
                ani.cancel();
            }
            removeAll();
            mDataChanged = false;

            initData();
        }

        if (mAutoSwitch && mAdapter.getItemCount() > 1) {
            //  mAutoSwitchHandler.removeMessages(MSG_AUTO_SWITCH);
            mAutoSwitchHandler.removeEvent(MSG_AUTO_SWITCH);
            //  mAutoSwitchHandler.sendEmptyMessageDelayed(MSG_AUTO_SWITCH, mStayTime);
            mAutoSwitchHandler.sendEvent(MSG_AUTO_SWITCH, mStayTime);
        }
    }

//    @Override
//    protected void onAttachedToWindow() {
//        super.onAttachedToWindow();
//        refresh();
//    }

    private void initData() {
        mCurPos = 0;

        int count = mAdapter.getItemCount();
        if (1 == count) {
            if (getChildCount() == 0) {
                add(mCurPos);
            } else {
                replace(mCurPos);
            }
            mCanSlide = false;
        } else if (count > 1) {
            int pre = (mCurPos - 1);
            if (pre < 0) {
                pre += count;
            }
            int next = (mCurPos + 1) % count;
            if (mLayoutNormal) {
                if (getChildCount() == 0) {
                    if (mCanSlide) {
                        //adding two children is enough to improve performance
                        add(pre);
                    }
                    add(mCurPos);
                    add(next);
                } else {
                    int index = 0;
                    if (mCanSlide) {
                        //adding two children is enough to improve performance
                        replace(pre, index++);
                    }
                    replace(mCurPos, index++);
                    replace(next, index++);
                }
            } else {
                if (getChildCount() == 0) {
                    add(next);
                    add(mCurPos);
                    if (mCanSlide) {
                        //adding two children is enough to improve performance
                        add(pre);
                    }
                } else {
                    int index = 0;
                    replace(next, index++);
                    replace(mCurPos, index++);
                    if (mCanSlide) {
                        //adding two children is enough to improve performance
                        replace(pre, index++);
                    }
                }
            }
        }

        if (count > 0 && null != mListener) {
            mListener.onPageFlip(1, count);
        }
    }

    protected void add(int pos) {
        add(pos, -1);
    }

    protected void add(int pos, int index) {
        int type = mAdapter.getType(pos);
        List<Adapter.ViewHolder> items = mItemCache.get(type, null);
        Adapter.ViewHolder vh;
        if (null != items && items.size() > 0) {
            vh = items.remove(0);
            vh.mPos = pos;
        } else {
            vh = mAdapter.onCreateViewHolder(type);
            vh.mType = type;
            vh.mPos = pos;
        }

        mAdapter.onBindViewHolder(vh, pos);

        if (index < 0) {
            // this.addView(vh.mItemView);
            this.addComponent(vh.mItemView);
        } else {
            // this.addView(vh.mItemView, index);
            this.addComponent(vh.mItemView, index);
        }

        vh.mItemView.invalidate();
    }

    private void replace(int pos) {
        replace(pos, -1);
    }

    protected void replace(int pos, int index) {
        Component itemView = null;
        int childCount = getChildCount();
        if (childCount == 0 || index >= childCount) {
            Log.d(TAG, "childCount == 0 or index >= childCount should not happen here");
            return;
        }
        if (index == -1) {
            // itemView = getChildAt(childCount - 1);
            itemView = getComponentAt(childCount - 1);
        } else {
            //itemView = getChildAt(index);
            itemView = getComponentAt(index);
        }
        Adapter.ViewHolder vh = (Adapter.ViewHolder) itemView.getTag();
        if (vh == null) {
            Log.d(TAG, "view holder == null, should not happen ");
            return;
        }
        mAdapter.onBindViewHolder(vh, pos);
    }

    private void acquireVelocityTracker(final /*MotionEvent*/TouchEvent event) {
        if (null == mVelocityTracker) {
            mVelocityTracker = VelocityDetector.obtainInstance();
//            mVelocityTracker = VelocityTracker.obtain();
        }
        //  mVelocityTracker.addMovement(event);
        mVelocityTracker.addEvent(event);
    }

    private void releaseVelocityTracker() {
        if (null != mVelocityTracker) {
            mVelocityTracker.clear();
            //  mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }


//    @Override TODO
//    public boolean onInterceptTouchEvent(MotionEvent ev) {
//        boolean ret = false;
//
//        if (mCanSlide) {
//            int x = (int) ev.getX();
//            int y = (int) ev.getY();
//            switch (ev.getAction()) {
//                case MotionEvent.ACTION_DOWN:
//                    if (mIsHorizontal) {
//                        mDownPos = x;
//                    } else {
//                        mDownPos = y;
//                    }
//                    mLastX = x;
//                    mLastY = y;
//                    mPointerId = ev.getPointerId(0);
//                    break;
//
//                case MotionEvent.ACTION_MOVE:
//                    int deltaX = x - mLastX;
//                    int deltaY = y - mLastY;
//
//                    if (mIsHorizontal) {
//                        if (Math.abs(deltaX) > Math.abs(deltaY)) {
//                            this.getParent().requestDisallowInterceptTouchEvent(true);
//                            ret = true;
//                        }
//                    } else {
//                        if (Math.abs(deltaY) > Math.abs(deltaX)) {
//                            this.getParent().requestDisallowInterceptTouchEvent(true);
//                            ret = true;
//                        }
//                    }
//                    break;
//
//                case MotionEvent.ACTION_UP:
//                    break;
//            }
//        }
//
//        return ret;
//    }

    private void moveV(TouchEvent event) {
        // int y = (int) event.getY();
        int y = (int) event.getPointerPosition(0).getY();
        switch (event.getAction()) {
            // case MotionEvent.ACTION_DOWN:
            case TouchEvent.PRIMARY_POINT_DOWN:
                mDownPos = y;
                break;

            // case MotionEvent.ACTION_MOVE:
            case TouchEvent.POINT_MOVE:
                int offset = y - mDownPos;
                this.setScrollY(-offset);
                break;

//            case MotionEvent.ACTION_CANCEL:
//            case MotionEvent.ACTION_UP:
            case TouchEvent.CANCEL:
            case TouchEvent.PRIMARY_POINT_UP:
                //   mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
                mVelocityTracker.calculateCurrentVelocity(1000, mMaxVelocity, mMaxVelocity);
                // final float velocityY = mVelocityTracker.getYVelocity(mPointerId);
                final float velocityY = mVelocityTracker.getVerticalVelocity();
                // animator
                // int scrollY = this.getScrollY();
                int scrollY = this.getScrollValue(VERTICAL);
                // int h = this.getMeasuredHeight();
                int h = this.getEstimatedHeight();
                int dis = Math.abs(scrollY);
                if (dis > h / 2 || Math.abs(velocityY) > VEL_THRESHOLD) {
                    if (scrollY < 0) {
                        mIsNext = false;
                        //  ani = ObjectAnimator.ofInt(this, "scrollY", scrollY, -h);
                        //   ani = createAnimatorProperty().moveFromY(scrollY).moveToY(-h);
                    } else {
                        mIsNext = true;
                        //  ani = ObjectAnimator.ofInt(this, "scrollY", scrollY, h);
                        //  ani = createAnimatorProperty().moveFromY(scrollY).moveToY(h);
                    }
                    // ani.setDuration(mAnimatorTimeInterval).addListener(mAniListener);
                    // ani.setDuration(mAnimatorTimeInterval).setStateChangedListener(mAniListener);
                    //ani.setInterpolator(getTimeInterpolater());
                    //  ani.start();
                } else {
                    //ObjectAnimator.ofInt(this, "scrollY", scrollY, 0).setDuration(mAnimatorTimeInterval).start();
                    // createAnimatorProperty().moveFromY(scrollY).moveToY(0).setDuration(mAnimatorTimeInterval).start();
                }

                releaseVelocityTracker();
                break;
        }
    }

    private void moveH(/*MotionEvent*/ TouchEvent event) {
//        int x = (int) event.getX();
        int x = (int) event.getPointerPosition(0).getX();
        switch (event.getAction()) {
            //  case MotionEvent.ACTION_DOWN:
            case TouchEvent.PRIMARY_POINT_DOWN:
                mDownPos = x;
                break;

            //case MotionEvent.ACTION_MOVE:
            case TouchEvent.POINT_MOVE:
                int offset = x - mDownPos;
                this.setScrollX(-offset);
                break;

            // case MotionEvent.ACTION_CANCEL:
            case TouchEvent.CANCEL:
                // case MotionEvent.ACTION_UP:
            case TouchEvent.PRIMARY_POINT_UP:
                // mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
                mVelocityTracker.calculateCurrentVelocity(1000, mMaxVelocity, mMaxVelocity);
                // final float velocityX = mVelocityTracker.getXVelocity(mPointerId);
                final float velocityX = mVelocityTracker.getHorizontalVelocity();
                //final float velocityY = mVelocityTracker.getYVelocity(mPointerId);
//                final float velocityY = mVelocityTracker.getVerticalVelocity();

                // animator
                //   int scrollX = this.getScrollX();
                int scrollX = this.getScrollValue(HORIZONTAL);
                //  int w = this.getMeasuredWidth();
                int w = this.getEstimatedWidth();
                int dis = Math.abs(scrollX);
                ani = new AnimatorValue();
                ani.setDuration(mAnimatorTimeInterval);
                ani.setStateChangedListener(mAniListener);
                if (dis > w / 2 || Math.abs(velocityX) > VEL_THRESHOLD) {

                    if (scrollX < 0) {
                        mIsNext = false;
                        //  ani = ObjectAnimator.ofInt(this, "scrollX", scrollX, -w);
                        setHorizontalAnimator(ani, scrollX - (-w));
                    } else {
                        mIsNext = true;
                        // ani = ObjectAnimator.ofInt(this, "scrollX", scrollX, w);
                        setHorizontalAnimator(ani, scrollX - w);
                    }
                    //  ani.setDuration(mAnimatorTimeInterval).addListener(mAniListener);
                    //  ani.setInterpolator(getTimeInterpolater());

                } else {
                    //  ObjectAnimator.ofInt(this, "scrollX", scrollX, 0).setDuration(mAnimatorTimeInterval).start();
                    setHorizontalAnimator(ani, scrollX);
                }
                ani.start();
                releaseVelocityTracker();
                break;
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        if (mCanSlide) {
            acquireVelocityTracker(event);
            if (mIsHorizontal) {
                moveH(event);
            } else {
                moveV(event);
            }

            return true;
        }
        return false;
    }

//    @Override
//    public boolean onTouchEvent(MotionEvent event) {
//        if (mCanSlide) {
//            acquireVelocityTracker(event);
//
//            if (mIsHorizontal) {
//                moveH(event);
//            } else {
//                moveV(event);
//            }
//
//            return true;
//        } else {
//            return super.onTouchEvent(event);
//        }
//    }

    protected void removeAll() {
        int count = this.getChildCount();
        for (int i = 0; i < count; ++i) {
            removeData(i);
        }
        //this.removeAllViews();
        this.removeAllComponents();
    }

    private void removeData(int index) {
        //View v = this.getChildAt(index);
        Component v = this.getComponentAt(index);

        Adapter.ViewHolder vh = (Adapter.ViewHolder) v.getTag();
        ((IContainer) vh.mItemView).getVirtualView().reset();
        // List<Adapter.ViewHolder> items = mItemCache.get(vh.mType);
        List<Adapter.ViewHolder> items = mItemCache.get(vh.mType, null);
        if (null == items) {
            items = new ArrayList<>();
            mItemCache.put(vh.mType, items);
        }
        if (items.size() >= MAX_ITEM_COUNT) {
            // recycle
            items.remove(0);
        }
        items.add(vh);
    }

    private void remove(int index) {
        removeData(index);
        //this.removeViewAt(index);
        this.removeComponentAt(index);
    }

    private void setVerticalAnimator(AnimatorValue ani, int off) {
        ani.setValueUpdateListener((animatorValue, v) -> {
            int top = (int) (off * v);

        });
    }


    private void setHorizontalAnimator(AnimatorValue ani, int off) {
        ani.setValueUpdateListener((animatorValue, v) -> {
            int left = (int) (off * v);

        });
    }


    private void setScrollX(int x) {
        //setTranslationX(x);

    }

    private void setScrollY(int y) {
        //   setTranslationY(y);
    }

    private void changeChildren() {
        // remove old item
        if (mAdapter == null) {
            return;
        }
        int count = mAdapter.getItemCount();

        if (count <= 0 || this.getChildCount() <= 0) {
            return;
        }

        if (mIsNext) {
            if (mLayoutNormal) {
                remove(0);
            } else {
                remove(this.getChildCount() - 1);
            }
            mCurPos = (mCurPos + 1) % count;
            int pos = (mCurPos + 1) % count;
            if (mLayoutNormal) {
                add(pos);
            } else {
                add(pos, 0);
            }
        } else {
            if (mLayoutNormal) {
                remove(this.getChildCount() - 1);
            } else {
                remove(0);
            }

            mCurPos -= 1;
            if (mCurPos < 0) {
                mCurPos += count;
            }

            int pos = (mCurPos - 1);
            if (pos < 0) {
                pos += count;
            }
            if (mLayoutNormal) {
                add(pos, 0);
            } else {
                add(pos);
            }
        }

        //this.requestLayout();
        this.postLayout();
        if (mIsHorizontal) {
            this.setScrollX(0);
        } else {
            this.setScrollY(0);
        }

        if (mAutoSwitch) {
            // mAutoSwitchHandler.removeMessages(MSG_AUTO_SWITCH);
            mAutoSwitchHandler.removeEvent(MSG_AUTO_SWITCH);
            if (mCanSwitch) {
                //  mAutoSwitchHandler.sendEmptyMessageDelayed(MSG_AUTO_SWITCH, mStayTime);
                mAutoSwitchHandler.sendEvent(MSG_AUTO_SWITCH, mStayTime);
            }
        }
    }

    private void resetChildren() {
        if (mIsHorizontal) {
            this.setScrollX(0);
        } else {
            this.setScrollY(0);
        }
    }

    class MyAnimatorListener implements Animator.StateChangedListener {


        @Override
        public void onStart(Animator animator) {

        }

        @Override
        public void onStop(Animator animator) {

        }

        @Override
        public void onCancel(Animator animator) {
            resetChildren();
        }

        @Override
        public void onEnd(Animator animator) {
            changeChildren();

            if (null != mListener) {
                mListener.onPageFlip(mCurPos + 1, mAdapter.getItemCount());
            }
        }

        @Override
        public void onPause(Animator animator) {

        }

        @Override
        public void onResume(Animator animator) {

        }
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int width = EstimateSpec.getSize(widthMeasureSpec);
        int height = EstimateSpec.getSize(heightMeasureSpec);

        //TODO
//        this.measureChildren(Component.EstimateSpec.getSizeWithMode(width, Component.EstimateSpec.PRECISE),
//                Component.EstimateSpec.getSizeWithMode(height, Component.EstimateSpec.PRECISE));

        int childCount = getChildCount();

        for (int i = 0; i < childCount; i++) {
            Component componentAt = getComponentAt(i);
            componentAt.estimateSize(EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE),
                    EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE));
        }
        setEstimatedSize(width, height);
        return true;
    }


//    @Override
//    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        int width = Component.EstimateSpec.getSize(widthMeasureSpec);
//        int height = Component.EstimateSpec.getSize(heightMeasureSpec);
//
//        this.measureChildren(Component.EstimateSpec.makeMeasureSpec(width, Component.EstimateSpec.EXACTLY),
//                Component.EstimateSpec.makeMeasureSpec(height, Component.EstimateSpec.EXACTLY));
//
//        setMeasuredDimension(width, height);
//    }

    @Override
    public boolean onArrange(int l, int t, int r, int b) {
        int count = this.getChildCount();
        int w = r - l;
        int h = b - t;
        int offset = 0;

        if (mIsHorizontal) {
            if (mLayoutNormal && mCanSlide) {
                offset = -w;
            } else if (!mLayoutNormal) {
                offset = -w;
            }
            for (int i = 0; i < count; ++i) {
                Component child = this.getComponentAt(i);
                child.arrange(offset, 0, offset + w, h);
                offset += w;
            }
        } else {
            if (count > 1) {
                if (mLayoutNormal && mCanSlide) {
                    offset = -h;
                } else if (!mLayoutNormal) {
                    offset = -h;
                }
            }
            for (int i = 0; i < count; ++i) {
                Component child = this.getComponentAt(i);
                child.arrange(0, offset, w, offset + h);
                offset += h;
            }
        }


        return false;
    }

//    @Override
//    protected void onLayout(boolean changed, int l, int t, int r, int b) {
//        int count = this.getChildCount();
//        int w = r - l;
//        int h = b - t;
//        int offset = 0;
//
//        if (mIsHorizontal) {
//            if (mLayoutNormal && mCanSlide) {
//                offset = -w;
//            } else if (!mLayoutNormal) {
//                offset = -w;
//            }
//            for (int i = 0; i < count; ++i) {
//                View child = this.getChildAt(i);
//                child.layout(offset, 0, offset + w, h);
//                offset += w;
//            }
//        } else {
//            if (count > 1) {
//                if (mLayoutNormal && mCanSlide) {
//                    offset = -h;
//                } else if (!mLayoutNormal) {
//                    offset = -h;
//                }
//            }
//            for (int i = 0; i < count; ++i) {
//                View child = this.getChildAt(i);
//                child.layout(0, offset, w, offset + h);
//                offset += h;
//            }
//        }
//    }

//    private TimeInterpolator getTimeInterpolater() {
//        switch (mAnimationStyle) {
//            case ViewBaseCommon.ANIMATION_LINEAR:
//                return new LinearInterpolator();
//            case ViewBaseCommon.ANIMATION_DECELERATE:
//                return new DecelerateInterpolator();
//            case ViewBaseCommon.ANIMATION_ACCELERATE:
//                return new AccelerateInterpolator();
//            case ViewBaseCommon.ANIMATION_ACCELERATEDECELERATE:
//                return new AccelerateDecelerateInterpolator();
//            case ViewBaseCommon.ANIMATION_SPRING:
//                return new SpringInterpolator();
//            default:
//                return new LinearInterpolator();
//        }
//    }

//    static public class SpringInterpolator implements TimeInterpolator {
//
//        private static final float FACTOR = 4f;
//
//        @Override
//        public float getInterpolation(float input) {
//            return (float) (Math.pow(2, -10 * input) * Math.sin((input - FACTOR / 4) * (2 * PI) / FACTOR) + 1);
//        }
//    }
//
//    static public class DecelerateInterpolator implements TimeInterpolator {
//
//        private static final float FACTOR = 5.0f;
//
//        @Override
//        public float getInterpolation(float input) {
//            float result;
//            if (FACTOR == 1.0f) {
//                result = (float) (1.0f - (1.0f - input) * (1.0f - input));
//            } else {
//                result = (float) (1.0f - Math.pow((1.0f - input), 2 * FACTOR));
//            }
//            return result;
//        }
//    }

}
